#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "types.h"
#include "cpu.h"
#include "defs.h"
#include "err.h"

rv32_cpu_t default_cpu;

int
cpu_init (rv32_cpu_t * mycpu) {
    int stat;
    stat = 0;
    if(pthread_mutex_init(&mycpu->intr_mtx, NULL) == -1) {
        perror ("Unable to init mutex (intr)");
        stat |= E_CPU_INTERNAL_ERR;
        goto error;
    }
    if(pthread_mutex_init(&mycpu->csr_mtx, NULL) == -1) {
        perror ("Unable to init mutex (csr)");
        stat |= E_CPU_INTERNAL_ERR;
        goto error;
    }
    memset (mycpu->csrs, 0, MAX_CSR_NUM * sizeof (int32));
    memset (mycpu->regs, 0, MAX_XR_NUM * sizeof(int32));
    mycpu->pc = 0x0;
    mycpu->mode = CPU_MODE_M;
    mycpu->intr_enable = false;
    mycpu->intr_info.intrset = false;
    mycpu->intr_info.src = 0;
    success:
    return stat;
    error:
    return stat;
}

int 
cpu_reset (rv32_cpu_t * mycpu) {
    int stat;
    stat = 0;
    if (pthread_mutex_destroy (&mycpu->csr_mtx) == -1) {
        perror ("Unable to destroy mutex (csr)");
        stat |= E_CPU_INTERNAL_ERR;
        goto error;
    }
    if (pthread_mutex_destroy (&mycpu->intr_mtx) == -1) {
        perror ("Unable to destroy mutex (intr)");
        stat |= E_CPU_INTERNAL_ERR;
        goto error;
    }
    if ((stat = cpu_init(mycpu)) != 0) {
        fprintf (stderr, "Unale to init cpu.\n");
        goto error;
    }
    success:
    return stat;
    error:
    return stat;

}

bool
cpu_should_handle_intr (rv32_cpu_t * mycpu) {
    bool res;
    res = false;
    CPU_INTR_LOCK (mycpu);
    // 如果有中断发生
    if ((mycpu->intr_info.intrset) != 0) {
        res = true; // 返回true
        mycpu->intr_enable = false; // 关中断
    }
    CPU_INTR_UNLOCK (mycpu);
    return res;
}


int
cpu_raise_intr (rv32_cpu_t * mycpu, uint32 src) {
    int stat;
    stat = 0;
    CPU_INTR_LOCK(mycpu);
    // 可中断
    if (mycpu->intr_enable != 0) {
        mycpu->intr_info.intrset = true;
        mycpu->intr_info.isexp = false;
        mycpu->intr_info.isintr = true;
        mycpu->intr_info.src = src;
    }
    CPU_INTR_UNLOCK(mycpu);
    return stat;
}

int
cpu_raise_exp (rv32_cpu_t * mycpu, uint32 src) {
    int stat;
    stat = 0;
    CPU_INTR_LOCK(mycpu);
    // 可中断
    if (mycpu->intr_enable != 0) {
        mycpu->intr_info.intrset = true;
        mycpu->intr_info.isexp = true;
        mycpu->intr_info.isintr = false;
        mycpu->intr_info.src = src;
    }
    CPU_INTR_UNLOCK(mycpu);
    return stat;
}

int
cpu_csr_read (rv32_cpu_t * mycpu, uint32 addr) {
    int32 csr;
    
}

int
cpu_csr_write (rv32_cpu_t * mycpu, uint32 addr) {

}

int
cpu_run_until_stop (rv32_cpu_t * mycpu) {
    int stat;
    stat = 0;
    if (cpu_should_handle_intr (mycpu)) {
        stat |= cpu_do_intr (mycpu);
    } else {
        stat |= cpu_do_exec (mycpu);
    }
    if (stat != 0) {
        PRINT_ERROR (cpu_run_until_stop, stat);
    }
    return stat;
}

/*
 * 中断发生时:
 * 1.关中断(已完成)
 * 2.设置mepc, 异常:mepc=pc, 中断mepc=pc+4 (注:ECALL 结束时PC不加4)
 * 3.设置PC = mtvec
 * 4.设置mcause
 * 5.设置mtval
 * 6.设置MIE,MPIE,MPP MIE->1 MPIE->previous MIE MPP->previous STATUS
 */

int
cpu_do_intr (rv32_cpu_t * mycpu) {

}

int
cpu_do_exec (rv32_cpu_t * mycpu) {

}